/*
 * Author: Raúl Pardo Jiménez
 * Version: 1.0
 */
#ifndef _SYN_H
#define _SYN_H
/*
 * Sizes
 */
#define MAX_ACTION_SIZE 20
#define MAX_PROCESSVAR_SIZE 20
#define MAX_ID_LENGHT 1000
#define MAX_SYN_ACTIONS 100

/*
 * Node Types
 */
#define SEQ_PROC 1
#define PARALLEL 2
#define EXT_CHO 3
#define PR_CHO 4
#define IN_CHO 5
#define PREFIX 6
#define ACTION 7
#define REC_VAR 8

/*
 * Elements
 */
typedef struct {
        /*
         * Common attributes
         */
        char key[MAX_ID_LENGHT];
        int type;

        /*
         * Action attributes
         */
        double time;
        char actionName[MAX_ACTION_SIZE];

        /*
         * Recursivity variable attributes
         */
        char variableName[MAX_PROCESSVAR_SIZE];

        /*
         * Probability
         */
        double probability;

        /*
         * Number of actions in the synchronization set
         */
        int numberOfActions;

        /*
         * Synchronization set
         */
        char actions[MAX_SYN_ACTIONS][MAX_ACTION_SIZE];

        /*
         * Sons
         */
        struct Node* left;
        struct Node* right;
} Node;

void sT_create_SEQ_PROC(char *key, Node *seq_proc) {

//      Node *seq_proc = (Node *) malloc(sizeof(Node));

        strcpy(seq_proc->key, key);
        seq_proc->type = SEQ_PROC;
        seq_proc->time = 0;
        strcpy(seq_proc->actionName, "");
        strcpy(seq_proc->variableName, "");
        seq_proc->probability = 0;
        seq_proc->numberOfActions = 0;
//      seq_proc->actions = NULL;
        seq_proc->left = NULL;
        seq_proc->right = NULL;

//      return seq_proc;
}

void sT_create_PARALLEL(char *key, char **actions, Node *par) {

//      Node *par = (Node *) malloc(sizeof(Node));

        strcpy(par->key, key);
        par->type = PARALLEL;
        par->time = 0;
        strcpy(par->actionName, "");
        strcpy(par->variableName, "");
        par->probability = 0;
        par->numberOfActions = 0;

        memcpy(par->actions, actions, sizeof(char **));

        par->left = NULL;
        par->right = NULL;

//      return par;
}

void sT_create_EXT_CHO(char *key, Node *ext_cho) {
//      Node *ext_cho = (Node *) malloc(sizeof(Node));

        strcpy(ext_cho->key, key);
        ext_cho->type = EXT_CHO;
        ext_cho->time = 0;
        strcpy(ext_cho->actionName, "");
        strcpy(ext_cho->variableName, "");
        ext_cho->probability = 0;
        ext_cho->numberOfActions = 0;
//      ext_cho->actions = NULL;
        ext_cho->left = NULL;
        ext_cho->right = NULL;

//      return ext_cho;
}
void sT_create_PR_CHO(char *key, float probability, Node *pr_cho) {
//      Node *pr_cho = (Node *) malloc(sizeof(Node));

        strcpy(pr_cho->key, key);
        pr_cho->type = PR_CHO;
        pr_cho->time = 0;
        strcpy(pr_cho->actionName, "");
        strcpy(pr_cho->variableName, "");
        pr_cho->probability = probability;
        pr_cho->numberOfActions = 0;
//      pr_cho->actions = NULL;
        pr_cho->left = NULL;
        pr_cho->right = NULL;

//      return pr_cho;
}

void sT_create_IN_CHO(char *key, Node *in_cho) {
//      Node *in_cho = (Node *) malloc(sizeof(Node));

        strcpy(in_cho->key, key);
        in_cho->type = IN_CHO;
        in_cho->time = 0;
        strcpy(in_cho->actionName, "");
        strcpy(in_cho->variableName, "");
        in_cho->probability = 0;
        in_cho->numberOfActions = 0;
//      in_cho->actions = NULL;
        in_cho->left = NULL;
        in_cho->right = NULL;

//      return in_cho;
}
void sT_create_PREFIX(char *key, Node *prefix) {
//      Node *prefix = (Node *) malloc(sizeof(Node));

        strcpy(prefix->key, key);
        prefix->type = PREFIX;
        prefix->time = 0;
        strcpy(prefix->actionName, "");
        strcpy(prefix->variableName, "");
        prefix->probability = 0;
        prefix->numberOfActions = 0;
//      prefix->actions = NULL;
        prefix->left = NULL;
        prefix->right = NULL;

//      return prefix;

}
void sT_create_ACTION(char *key, char *actionName, float time, Node *action) {
//      Node *action = (Node *) malloc(sizeof(Node));

        strcpy(action->key, key);
        action->type = ACTION;
        action->time = time;
        strcpy(action->actionName, actionName);
        strcpy(action->variableName, "");
        action->probability = 0;
        action->numberOfActions = 0;
//      action->actions = NULL;
        action->left = NULL;
        action->right = NULL;

//      return action;
}

void sT_create_REC_VAR(char *key, char *variableName, Node *variable) {
//      Node *variable = (Node *) malloc(sizeof(Node));

        strcpy(variable->key, key);
        variable->type = REC_VAR;
        variable->time = 0;
        strcpy(variable->actionName, "");
        strcpy(variable->variableName, variableName);
        variable->probability = 0;
        variable->numberOfActions = 0;
//      variable->actions = NULL;
        variable->left = NULL;
        variable->right = NULL;

//      return variableName;
}

int sT_getType(Node *node) {
        return node->type;
}

int sT_isOperator(int nodeType) {
        if (nodeType < 7) {
                return 1;
        }
        return 0;
}

/*
 * This function release memory of a whole
 * tree, in order to avoid the waste of memory
 * arisen by residual nodes
 */
void recursiveFree(Node *tree) {
//      if (tree->left==NULL && tree->right==NULL)

        if (tree->left) {
                recursiveFree(tree->left);
        }
        if (tree->right) {
                recursiveFree(tree->right);
        }
        free(tree);

}

/*
 * This function return a pointer to a node with
 * the key used as parameter if it exist, e.o.c
 * it returns null.
 */
Node* sT_getNode(Node *tree, char *searchedkey) {
        if (tree) {
                if (strcmp(tree->key, searchedkey) == 0) {
                        return tree;
                } else {
                        if (tree->left) {
                                Node *temp = (Node *) sT_getNode(tree->left, searchedkey);
                                if (temp) {
                                        return temp;
                                }
                        }

                        if (tree->right) {
                                Node *temp = (Node *) sT_getNode(tree->right, searchedkey);
                                if (temp) {
                                        return temp;
                                }
                        }
                }
        }
        return NULL;
}

/*
 * This function returns a pointer of the
 * father node of node used as input.
 */
Node* sT_getFatherNode(Node *tree, char *sonsKey) {

        int length = strlen(sonsKey);
        char *fatherId = (char *) malloc(sizeof(char) * (length - 1));
        strncpy(fatherId, sonsKey, length - 1);

        return sT_getNode(tree, fatherId);
}

/*
 * This function removes a node by means of pointing
 * to null the pointer of its father to that son
 */
void sT_removeNode(Node *tree) {
        /*Node *aux;*/
        if (tree) {
                if (tree->left) {
                        sT_removeNode(tree->left);
                }
                if (tree->right) {
                        sT_removeNode(tree->right);
                }
//              printf("%p is going to be deleted \n",tree);
                tree = NULL;
                free(tree);
//              printf("Done! %p deteled\n",tree);
        }
}

/*
 * This function is used to add new nodes to a syntactic tree which is taken as
 * parameter. The nodes key must be right formed in order to locate in a right
 * place the node. On the other hand, it currently doesn't have an error function
 * so as to notify possible mistakes inside the execution of this function.
 */
//void sT_addNode(Node *tree, Node *node, int level) {
//      /*
//       * It is checked if the tree is empty
//       */
//      if (tree == NULL) {
//              printf("The node is null\n");
//              tree = (Node *)malloc(sizeof(Node));
//
//              tree = node;
//
//              printf("The id of the added node is %s \n",tree->key);
//      } else {
//              printf("The node is not null\n");
//              /*
//               * If the tree it is not empty, the algorithm starts
//               * going down over the tree in order to find the proper
//               * leaf to locate the new node.
//               */
//              level = level + 1;
//              if (node->key[level] == '0') {
//
//                      if (tree->left == NULL) {
//                              tree->left = (Node *) malloc(sizeof(Node));
//                              sT_addNode(tree->left, node, level);
//                      } else {
//                              sT_addNode(tree->left, node, level);
//                      }
//
//              }
//              if (node->key[level] == '1') {
//
//                      if (tree->right == NULL) {
//                              tree->right = (Node *) malloc(sizeof(Node));
//                              sT_addNode(tree->right, node, level);
//                      } else {
//                              sT_addNode(tree->right, node, level);
//                      }
//              }
//      }
//}
Node *sT_addNode(Node *tree, Node *nodeToAdd) {

        if (!tree) {
//              printf("There is no node\n");
//                tree = (Node *) malloc(sizeof(Node));
//                tree = nodeToAdd;
//              strcpy(tree->key,nodeToAdd->key);
                return nodeToAdd;
                printf("The tree is null %s \n", tree->key);
        } else {
                char lastIdBit = nodeToAdd->key[strlen(tree->key)];

                if (lastIdBit == '0') {
                        tree->left = sT_addNode(tree->left, nodeToAdd);

                } else if (lastIdBit == '1') {
                        tree->right = sT_addNode(tree->right, nodeToAdd);
                }
        }
        return tree;
}

int isUpperCase(char a) {
        if (a == 'A' || a == 'B' || a == 'C' || a == 'D' || a == 'E' || a == 'F'
                        || a == 'G' || a == 'H' || a == 'I' || a == 'J' || a == 'K'
                        || a == 'L' || a == 'M' || a == 'N' || a == 'O' || a == 'P'
                        || a == 'Q' || a == 'R' || a == 'S' || a == 'T' || a == 'U'
                        || a == 'V' || a == 'W' || a == 'X' || a == 'Y' || a == 'Z') {

                return 1;
        }
        return 0;
}

int isLowerCase(char a) {
        if (a == 'a' || a == 'b' || a == 'c' || a == 'd' || a == 'e' || a == 'f'
                        || a == 'g' || a == 'h' || a == 'i' || a == 'j' || a == 'k'
                        || a == 'l' || a == 'm' || a == 'n' || a == 'o' || a == 'p'
                        || a == 'q' || a == 'r' || a == 's' || a == 't' || a == 'u'
                        || a == 'v' || a == 'w' || a == 'x' || a == 'y' || a == 'z') {

                return 1;
        }
        return 0;
}

int getClosingParenthesis(char *expression, int openningPosition) {
        //Se comprueba que la posición de indicada corresponde a la apertura de
        //un parentesis
        if (expression[openningPosition] != '(') {
                return -1;
        }

        int aperturaParentesis = 0;
        int cierreParentesis = 0;
        int coincidencia = 0;
        int coincidenciaEncontrada = 0;

        int length = strlen(expression);
        int i;
        for (i = openningPosition; i < length; i++) {
                char c = expression[i];

                if (c == '(') {
                        aperturaParentesis++;
                }
                if (c == ')' /*&& aperturaParentesis != cierreParentesis*/) {
                        cierreParentesis++;
                        if (aperturaParentesis == cierreParentesis) {
                                if (i == openningPosition + 1) {
                                        coincidencia = -1;

                                } else if (coincidenciaEncontrada == 0) {
                                        coincidenciaEncontrada++;
                                        coincidencia = i;

                                }
                        }
                }
        }

        if (aperturaParentesis == cierreParentesis) {
                return coincidencia;
        }

        return -1;
}

Node *sT_getSyntacticTree(Node *tree, char *mathematicalExpression,
                char *nodeKey) {

        int length = strlen(mathematicalExpression);

        if (length < 1) {
                printf("The mathematical expression haven't got nodes\n");
                return NULL;
        }

        if (mathematicalExpression[0] == '('
                        && getClosingParenthesis(mathematicalExpression, 0) == length - 1) {
                printf("Complete expression to delete its parenthesis: %s\n",
                                mathematicalExpression);
                mathematicalExpression[0] = ' ';
                mathematicalExpression[length - 1] = ' ';

                char *temp = (char *) malloc(sizeof(char) * length);

                strcpy(temp, mathematicalExpression);
                temp++;

                char *newMathematicalExpression = (char *) malloc(
                                sizeof(char) * (length - 2));

                strncpy(newMathematicalExpression, temp, strlen(temp) - 1);

                return sT_getSyntacticTree(tree, newMathematicalExpression, nodeKey);

//              return;
        }

        int i;
        /*
         * Searching for ; operators
         */
        for (i = 0; i < length; i++) {
                char c = mathematicalExpression[i];
                if (c == '(') {
                        int tem = getClosingParenthesis(mathematicalExpression, i);
                        if (tem != -1) {
                                i = tem;
                        }
                }

                if (c == ';') {

//                      Node newNode = { nodeKey, SEQ_PROC, 0, "", "", 0, 0, NULL, NULL,
//                                      NULL };

                        Node *newNode = (Node *) malloc(sizeof(Node));
                        sT_create_SEQ_PROC(nodeKey, newNode);
                        tree = sT_addNode(tree, newNode);

                        /*
                         * Getting subprocesses of the ; operator
                         */
                        char *leftMathematicalExpression = (char *) malloc(
                                        sizeof(char) * i);
                        char *rightMathematicalExpression = (char *) malloc(
                                        sizeof(char) * (length - (i + 1)));

                        strncpy(leftMathematicalExpression, mathematicalExpression, i);
                        mathematicalExpression += (i + 1);
                        strncpy(rightMathematicalExpression, mathematicalExpression,
                                        length - (i + 1));

                        char *nodeKeyLeftSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);
                        char *nodeKeyRightSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);

                        strcpy(nodeKeyLeftSon, nodeKey);
                        strcpy(nodeKeyRightSon, nodeKey);

                        strcat(nodeKeyLeftSon, "0");
                        strcat(nodeKeyRightSon, "1");

//                      printf("New keys for nodes %s, %s \n",leftMathematicalExpression,rightMathematicalExpression);

//                      tree->left = (Node *) malloc(sizeof(Node));
//                      Node *left = tree->left;
//                      Node *right = tree->right;

                        sT_getSyntacticTree(tree, leftMathematicalExpression,
                                        nodeKeyLeftSon);

//                      tree->right = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, rightMathematicalExpression,
                                        nodeKeyRightSon);

                        return tree;
                }
        }

        /*
         * Searching for parallel operators
         */
        for (i = 0; i < length; i++) {
                char c = mathematicalExpression[i];

                if (c == '(') {
                        int tem = getClosingParenthesis(mathematicalExpression, i);
                        if (tem != -1) {
                                i = tem;
                        }
                }

                if (c == '|') {

//                      Node newNode = { nodeKey, PARALLEL, 0, "", "", 0, 0, NULL, NULL,
//                                      NULL };

                        Node *newNode = (Node *)malloc(sizeof(Node));
                        char tempSet[MAX_SYN_ACTIONS][MAX_ACTION_SIZE];
                        sT_create_PARALLEL(nodeKey,tempSet,newNode);

                        int j = i + 3;
//                      char **actions = (char **) malloc(sizeof(char *) * 50);
                        char actions[MAX_SYN_ACTIONS][MAX_ACTION_SIZE];
                        char *syncSet;
                        int cont = 0;
                        for (; mathematicalExpression[j] != '}'; j++) {
                                cont++;
                        }
                        syncSet = (char *) malloc(sizeof(char) * cont);
                        char *temp = (char *) malloc(
                                        sizeof(char) * strlen(mathematicalExpression));
                        strcpy(temp, mathematicalExpression);
                        temp += (i + 3);
                        strncpy(syncSet, temp, cont);
//                      printf("The synchronization set is %s \n",syncSet);

                        char * pch;
                        pch = strtok(syncSet, ",");

                        while (pch != NULL) {
                                sT_insertAction(newNode, pch);
                                pch = strtok(NULL, ",");
                        }

                        tree = sT_addNode(tree, newNode);
                        int extraSpace = cont + 3;
                        /*
                         * Getting subprocesses of the ; operator
                         */
                        char *leftMathematicalExpression = (char *) malloc(
                                        sizeof(char) * i);
                        char *rightMathematicalExpression = (char *) malloc(
                                        sizeof(char) * (length - (i + 1 + extraSpace)));

                        strncpy(leftMathematicalExpression, mathematicalExpression, i);
                        mathematicalExpression += (i + 1 + extraSpace);
                        strncpy(rightMathematicalExpression, mathematicalExpression,
                                        length - (i + 1 + extraSpace));

                        char *nodeKeyLeftSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);
                        char *nodeKeyRightSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);

                        strcpy(nodeKeyLeftSon, nodeKey);
                        strcpy(nodeKeyRightSon, nodeKey);

                        strcat(nodeKeyLeftSon, "0");
                        strcat(nodeKeyRightSon, "1");

//                      printf("New keys for nodes %s, %s \n",leftMathematicalExpression,rightMathematicalExpression);

//                      tree->left = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, leftMathematicalExpression,
                                        nodeKeyLeftSon);

//                      tree->right = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, rightMathematicalExpression,
                                        nodeKeyRightSon);

                        return tree;
                }
        }

        /*
         * Searching for external, internal and probabilistic choices
         */
        for (i = 0; i < length; i++) {
                char c = mathematicalExpression[i];

                if (c == '(') {
                        int tem = getClosingParenthesis(mathematicalExpression, i);
                        if (tem != -1) {
                                i = tem;
                        }
                }

                if (c == '+' || c == '-' || c == '*') {
                        int extraSpace = 0;
//                      Node newNode = { nodeKey, 0, 0, "", "", 0, 0, NULL, NULL, NULL };
                        Node *newNode = (Node *)malloc(sizeof(Node));

                        if (c == '+') {
                                sT_create_EXT_CHO(nodeKey,newNode);
//                              newNode.type = EXT_CHO;
                        }
                        if (c == '-') {
                                sT_create_IN_CHO(nodeKey,newNode);
//                              newNode.type = IN_CHO;
                        }
                        if (c == '*') {
                                int j = i;
                                //I take 50 chars of memory but it had better to not waste memory and save only needed memory
                                int cont = 0;
                                char *probabilityString;
                                for (j += 2; mathematicalExpression[j] != '}'; j++) {
                                        if (mathematicalExpression[j] == '0'
                                                        || mathematicalExpression[j] == '1'
                                                        || mathematicalExpression[j] == '.'
                                                        || mathematicalExpression[j] == '2'
                                                        || mathematicalExpression[j] == '3'
                                                        || mathematicalExpression[j] == '4'
                                                        || mathematicalExpression[j] == '5'
                                                        || mathematicalExpression[j] == '6'
                                                        || mathematicalExpression[j] == '7'
                                                        || mathematicalExpression[j] == '8'
                                                        || mathematicalExpression[j] == '9') {
                                                cont++;
                                        }

                                        probabilityString = (char *) malloc(sizeof(char) * cont);
                                        char *temp = (char *) malloc(
                                                        sizeof(char) * strlen(mathematicalExpression));
                                        strcpy(temp, mathematicalExpression);
                                        temp += (i + 2);
                                        strncpy(probabilityString, temp, cont);

                                }
                                double probability = atof(probabilityString);
                                extraSpace += (cont + 2);
//                              newNode.type = PR_CHO;
//                              newNode.probability = probability;
                                sT_create_PR_CHO(nodeKey,probability,newNode);
                        }

                        tree = sT_addNode(tree, newNode);

                        /*
                         * Getting subprocesses of the ; operator
                         */
                        char *leftMathematicalExpression = (char *) malloc(
                                        sizeof(char) * i);
                        char *rightMathematicalExpression = (char *) malloc(
                                        sizeof(char) * (length - (i + 1 + extraSpace)));

                        strncpy(leftMathematicalExpression, mathematicalExpression, i);
                        mathematicalExpression += (i + 1 + extraSpace);
                        strncpy(rightMathematicalExpression, mathematicalExpression,
                                        length - (i + 1 + extraSpace));

                        char *nodeKeyLeftSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);
                        char *nodeKeyRightSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);

                        strcpy(nodeKeyLeftSon, nodeKey);
                        strcpy(nodeKeyRightSon, nodeKey);

                        strcat(nodeKeyLeftSon, "0");
                        strcat(nodeKeyRightSon, "1");

//                      printf("New keys for nodes %s, %s \n",leftMathematicalExpression,rightMathematicalExpression);

//                      tree->left = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, leftMathematicalExpression,
                                        nodeKeyLeftSon);

//                      tree->right = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, rightMathematicalExpression,
                                        nodeKeyRightSon);

                        return tree;
                }
        }

        for (i = 0; i < length; i++) {
                char c = mathematicalExpression[i];
                if (c == '(') {
                        int tem = getClosingParenthesis(mathematicalExpression, i);
                        if (tem != -1) {
                                i = tem;
                        }
                }

                /*
                 * If it finds some < character that means an action
                 * is being defined, so we should skip its content in
                 * order to avoid confusing the . character of the decimal
                 * part of the temporal exponential distribution.
                 */
                if (c == '<') {
                        while (c != '>') {
                                i++;
                                c = mathematicalExpression[i];
                        }
                }

                if (c == '.') {
//                      Node newNode =
//                                      { nodeKey, PREFIX, 0, "", "", 0, 0, NULL, NULL, NULL };
                        Node *newNode = (Node *)malloc(sizeof(Node));
                        sT_create_PREFIX(nodeKey,newNode);
                        tree = sT_addNode(tree, newNode);

                        /*
                         * Getting subprocesses of the . operator
                         */
                        char *leftMathematicalExpression = (char *) malloc(
                                        sizeof(char) * i);
                        char *rightMathematicalExpression = (char *) malloc(
                                        sizeof(char) * (length - (i + 1)));

                        strncpy(leftMathematicalExpression, mathematicalExpression, i);
                        mathematicalExpression += (i + 1);
                        strncpy(rightMathematicalExpression, mathematicalExpression,
                                        length - (i + 1));

                        char *nodeKeyLeftSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);
                        char *nodeKeyRightSon = (char *) malloc(
                                        sizeof(char) * MAX_ID_LENGHT);

                        strcpy(nodeKeyLeftSon, nodeKey);
                        strcpy(nodeKeyRightSon, nodeKey);

                        strcat(nodeKeyLeftSon, "0");
                        strcat(nodeKeyRightSon, "1");

//                      printf("New keys for nodes %s, %s \n",leftMathematicalExpression,rightMathematicalExpression);

//                      tree->left = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, leftMathematicalExpression,
                                        nodeKeyLeftSon);

//                      tree->right = (Node *) malloc(sizeof(Node));
                        sT_getSyntacticTree(tree, rightMathematicalExpression,
                                        nodeKeyRightSon);

                        return tree;
                }
        }

        for (i = 0; i < length; i++) {
                char c = mathematicalExpression[i];

                if (c == '<') {

                        int j = i + 1;
                        int cont = 0;

                        while (mathematicalExpression[j] != '>') {
                                j++;
                                cont++;
                        }
                        char *temp = (char *) malloc(
                                        sizeof(char *) * strlen(mathematicalExpression));
                        strcpy(temp, mathematicalExpression);
                        temp += (i + 1);
                        char *actionTime = (char *) malloc(sizeof(char) * cont);
                        strncpy(actionTime, temp, cont);

                        char * pch;
                        pch = strtok(actionTime, ",");

                        char **actTime = (char **) malloc(sizeof(char *) * 2);
                        int k = 0;
                        while (pch != NULL) {
                                actTime[k] = pch;
                                pch = strtok(NULL, ",");
                                k++;
                        }
                        printf("%s,%s\n", actTime[0], actTime[1]);
//                      Node action1 =
//                                      { nodeKey, ACTION, 0, "", "", 0, 0, NULL, NULL, NULL };
                        Node *action1 = (Node *)malloc(sizeof(Node));
                        sT_create_ACTION(nodeKey,actTime[0],atof(actTime[1]),action1);
//                      strcpy(action1.actionName, actTime[0]);
//                      action1.time = atof(actTime[1]);

                        tree = sT_addNode(tree, action1);
                        return tree;
                }

                if (isLowerCase(c)) {

                        int j = 0;
                        char action[MAX_ACTION_SIZE];

                        while (isLowerCase(mathematicalExpression[i])) {
                                j++;
                                i++;
                        }
                        /*
                         * To check if the maximum action length has been
                         * exceeded
                         */
                        if (j > MAX_ACTION_SIZE) {
                                printf("The maximum action size has been exceeded\n");
                                return NULL;
                        }
                        strncpy(action, mathematicalExpression, j + 1);
//                      Node action1 =
//                                      { nodeKey, ACTION, 0, "", "", 0, 0, NULL, NULL, NULL };


                        Node *action1 = (Node *) malloc(sizeof(Node));
                        sT_create_ACTION(nodeKey, action, 0, action1);

//                      strncpy(action1.actionName, action, strlen(action));
                        tree = sT_addNode(tree, action1);
                        return tree;
                }

                if (c == '0') {

                        char action[MAX_ACTION_SIZE];
                        action[0] = c;
                        action[1] = '\0';

//                      Node action1 =
//                                      { nodeKey, ACTION, 0, "", "", 0, 0, NULL, NULL, NULL };
                        Node *action1 = (Node *)malloc(sizeof(Node));
                        sT_create_ACTION(nodeKey,action,0,action1);
//                      strcpy(action1.actionName, action);
                        tree = sT_addNode(tree, action1);

                        return tree;
                }

                if (isUpperCase(c)) {

                        int j = 0;
                        char variable[MAX_ACTION_SIZE];

                        while (isUpperCase(mathematicalExpression[i])) {
                                j++;
                                i++;
                        }
                        /*
                         * To check if the maximum action length has been
                         * exceeded
                         */
                        if (j > MAX_PROCESSVAR_SIZE) {
                                printf("The maximum action size has been exceeded\n");
                                return NULL;
                        }
                        strncpy(variable, mathematicalExpression, j + 1);
//                      Node action1 =
//                                      { nodeKey, REC_VAR, 0, "", "", 0, 0, NULL, NULL, NULL };
                        Node *action1 = (Node *)malloc(sizeof(Node));
                        sT_create_REC_VAR(nodeKey,variable,action1);
//                      strncpy(action1.variableName, variable, strlen(variable));
                        tree = sT_addNode(tree, action1);
                        return tree;
                }

        }

        return tree;
}

/*
 * This function is used to determine if two actions names are equal
 * usually two strings with 20 characters
 */
int sT_equalActionName(char *actionName1, char *actionName2) {
        int i;
        for (i = 0; i < MAX_ACTION_SIZE; i++) {
                if (actionName1[i] != actionName2[i]) {
                        return 0; //FALSE
                }
        }
        return 1; //TRUE
}

/*
 * This function is used to determine if two process variables names are equal
 * usually two strings with 20 characters
 */
int sT_equalProcessVarName(char *processVarName1, char *processVarName2) {
        int i;
        for (i = 0; i < MAX_PROCESSVAR_SIZE; i++) {
                if (processVarName1[i] != processVarName2[i]) {
                        return 0; //FALSE
                }
        }
        return 1; //TRUE
}

/*
 * This function is used to determine if two synchronization sets cotains
 * the same actions
 */
int sT_equalSynchronizationSet(char **set1, int numberOfAction1, char **set2,
                int numberOfAction2) {

        int i;

        if (numberOfAction1 != numberOfAction2) {
                return 0;
        }

        for (i = 0; i < numberOfAction1; i++) {
                if (!sT_equalActionName(set1[i], set2[i])) {
                        return 0;
                }
        }

        return 1;
}

/*
 * This function is used to determine if two nodes are equal, comparing all
 * attributes defined in the structure node
 */
int sT_equalNode(Node *node1, Node *node2) {

        if ((node1->type == node2->type) && (node1->time == node2->time)
                        && sT_equalActionName(node1->actionName, node2->actionName)
                        && sT_equalProcessVarName(node1->variableName, node2->variableName)
                        && (node1->probability == node2->probability)
                        //&& (node1->numberOfActions == node2->numberOfActions) This is checked in the next condition
                        && sT_equalSynchronizationSet(node1->actions,
                                        node1->numberOfActions, node2->actions,
                                        node2->numberOfActions)) {
                return 1;
        }

        return 0;
}

/*
 * This functions is used to insert actions into the synchronization set
 * of parallel operators
 */
void sT_insertAction(Node *parallel, char *nombre) {
        /*
         * Update the number of actions in the synchronization set
         */
        if (parallel->numberOfActions < MAX_SYN_ACTIONS) {
                strcpy(parallel->actions[parallel->numberOfActions], nombre);
                parallel->numberOfActions++;
        } else {
                printf(
                                "Error: Can not be added more actions to this synchronization set of the node %s\n",
                                parallel->key);
        }

//      /*
//       * Checking if it is the first action in the synchronization set
//       */
//      if (parallel->numberOfActions == 1) {
//              /*
//               * Saving memory an array with only one element
//               */
//              parallel->actions = (char **) malloc(sizeof(char *));
//              /*
//               * Saving memory in for a char of 20 characters in memory previosly
//               * saved
//               */
//              parallel->actions[parallel->numberOfActions - 1] = (char *) malloc(
//                              sizeof(char) * MAX_ACTION_SIZE);
//              /*
//               * Inserting the name of action in the memory saved
//               */
//              strcpy(parallel->actions[parallel->numberOfActions - 1], nombre);
//
//      } else {
//              /*
//               * Reallocating memory space for the list of actions with one more
//               * slot
//               */
//              parallel->actions = realloc(parallel->actions,
//                              parallel->numberOfActions * sizeof(char *));
//              /*
//               * The same that in the other part of the if structure
//               */
//              parallel->actions[parallel->numberOfActions - 1] = (char *) malloc(
//                              sizeof(char) * MAX_ACTION_SIZE);
//              strcpy(parallel->actions[parallel->numberOfActions - 1], nombre);
//      }

}

void copyParallizationSet(Node *parallel, Node *targetNode) {
        if (parallel->actions == NULL) {
                printf(
                                "The parallel node %s doesn't have any action in its parallelization set\n",
                                parallel->key);
                return;
        }

//      char **paralizationSet = (char **) malloc(
//                      sizeof(char *) * parallel->numberOfActions);
        char paralizationSet[MAX_SYN_ACTIONS][MAX_ACTION_SIZE];
        int i;
        for (i = 0; i < parallel->numberOfActions; i++) {
//              paralizationSet[i] = (char *) malloc(sizeof(char) * MAX_ACTION_SIZE);
                sT_insertAction(targetNode,parallel->actions[i]);
//              strcpy(paralizationSet[i], parallel->actions[i]);
        }
//      return paralizationSet;
}

void getSubTree(Node *subTreeRoot, Node *output_node, char *key,
                int initialLevel) {
        if (subTreeRoot) {
//              printf("The subtree is not empty!\n");
                //              Node newNode = { rootKey, subTreeRoot->type, subTreeRoot->time, "", "",
                //                              subTreeRoot->probability, subTreeRoot->numberOfActions, NULL,
                //                              NULL, NULL };
                                Node *newNode = (Node *)malloc(sizeof(Node));
                //              newNode.key = (char *)malloc(sizeof(char)*strlen(rootKey));
                                strcpy(newNode->key, key);

                                newNode->type = subTreeRoot->type;
                                newNode->time = subTreeRoot->time;

                                newNode->probability = subTreeRoot->probability;
//                              newNode->numberOfActions = subTreeRoot->numberOfActions;

                                strcpy(newNode->actionName, subTreeRoot->actionName);
                                strcpy(newNode->variableName, subTreeRoot->variableName);
//                              memcpy(newNode->actions,copyParallizationSet(subTreeRoot),sizeof(char **));
                //              newNode.actions = copyParallizationSet(subTreeRoot);
                                copyParallizationSet(subTreeRoot, newNode);

                                newNode->left = NULL;
                                newNode->right = NULL;

                output_node = sT_addNode(output_node, newNode);

                if (subTreeRoot->left) {
                        char *newKey = (char *) malloc(sizeof(char) * MAX_ID_LENGHT);
                        strcpy(newKey, key);
                        strcat(newKey, "0");
//                      Node *leftNode = (Node *) malloc(sizeof(Node));
//                      leftNode = (Node *) subTreeRoot->left;
                        getSubTree(subTreeRoot->left, output_node, newKey, initialLevel);
                }

                if (subTreeRoot->right) {
                        char *newKey = (char *) malloc(sizeof(char) * MAX_ID_LENGHT);
                        strcpy(newKey, key);
                        strcat(newKey, "1");
//                      Node *rightNode = (Node *) malloc(sizeof(Node));
//                      rightNode = (Node *) subTreeRoot->right;
                        getSubTree(subTreeRoot->right, output_node, newKey, initialLevel);
                }
        }
}

Node *sT_getSubTree(Node *subTreeRoot, Node *output_node, char *rootKey) {

        if (subTreeRoot) {
//              printf("The tree is not empty!\n");
//              Node newNode = { rootKey, subTreeRoot->type, subTreeRoot->time, "", "",
//                              subTreeRoot->probability, subTreeRoot->numberOfActions, NULL,
//                              NULL, NULL };
                Node *newNode = (Node *)malloc(sizeof(Node));
//              newNode.key = (char *)malloc(sizeof(char)*strlen(rootKey));
                strcpy(newNode->key, rootKey);

                newNode->type = subTreeRoot->type;
                newNode->time = subTreeRoot->time;

                newNode->probability = subTreeRoot->probability;
//              newNode->numberOfActions = subTreeRoot->numberOfActions;

                strcpy(newNode->actionName, subTreeRoot->actionName);
                strcpy(newNode->variableName, subTreeRoot->variableName);
//              memcpy(newNode->actions,copyParallizationSet(subTreeRoot),sizeof(char **));
                copyParallizationSet(subTreeRoot, newNode);

                newNode->left = NULL;
                newNode->right = NULL;

                output_node = sT_addNode(output_node, newNode);

                char *leftKey = (char *) malloc(sizeof(char) * MAX_ID_LENGHT);
                char *rightKey = (char *) malloc(sizeof(char) * MAX_ID_LENGHT);

                strcpy(leftKey, rootKey);
                strcpy(rightKey, rootKey);

                strcat(leftKey, "0");
                strcat(rightKey, "1");

                if (subTreeRoot->left) {
//                      Node *leftNode = (Node *) malloc(sizeof(Node));
//                      leftNode = (Node *) subTreeRoot->left;
                        getSubTree(subTreeRoot->left, output_node, leftKey,
                                        strlen(rootKey) - 1);
                }

                if (subTreeRoot->right) {
//                      Node *rightNode = (Node *) malloc(sizeof(Node));
//                      rightNode = (Node *) subTreeRoot->right;
                        getSubTree(subTreeRoot->right, output_node, rightKey,
                                        strlen(rootKey) - 1);
                }
        }
        return output_node;
}

//void normalizePrefixes(Node *tree, char *prefix) {
//      if (tree) {
//
//              int prefixLength = strlen(prefix);
//              int idCurrentNodeLength = strlen(tree->key);
//
//              char *newKey = (char *) malloc(
//                              sizeof(char) * (prefixLength + idCurrentNodeLength));
//              strcpy(newKey, prefix);
//              strcat(newKey, tree->key);
//
//              tree->key = (char *) malloc(
//                              sizeof(char) * (prefixLength + idCurrentNodeLength));
//              strcpy(tree->key, newKey);
//
//              if (tree->right) {
//                      normalizePrefixes(tree->right, prefix);
//              }
//              if (tree->left) {
//                      normalizePrefixes(tree->left, prefix);
//              }
//      }
//}

void sT_replacingNode(Node *tree, char *keyNode, char *keyOldSon,
                char *keyNewSon) {

        Node *fatherOfNodeToBeReplaced = (Node *) malloc(sizeof(Node));
        fatherOfNodeToBeReplaced = sT_getNode(tree, keyNode);

        Node *leftSon = (Node *) malloc(sizeof(Node));
        leftSon = fatherOfNodeToBeReplaced->left;

        Node *rightSon = (Node *) malloc(sizeof(Node));
        rightSon = fatherOfNodeToBeReplaced->right;

        Node *nodeToBeReplaced = (Node *) malloc(sizeof(Node));
        nodeToBeReplaced = sT_getNode(tree, keyOldSon);

//      Node *leftSonToBeReplaced = (Node *) malloc(sizeof(Node));
//      leftSonToBeReplaced = nodeToBeReplaced->left;
//
        Node *nodeToBeEmplaced = (Node *) malloc(sizeof(Node));
        nodeToBeEmplaced = sT_getNode(tree, keyNewSon);

        Node *subTreeToLocate = NULL/*(Node *) malloc(sizeof(Node))*/;
        subTreeToLocate = sT_getSubTree(nodeToBeEmplaced, subTreeToLocate, keyOldSon);
        printf("From replacing a node [%p,%p]\n",subTreeToLocate->left,subTreeToLocate->right);

        if (strcmp(leftSon->key, keyOldSon) == 0) {
                Node *aux;
                aux = leftSon;
                fatherOfNodeToBeReplaced->left = (Node *) subTreeToLocate;
                sT_removeNode(aux);
                return;
        }

        if (strcmp(rightSon->key, keyOldSon) == 0) {
                Node *aux;
                aux = rightSon;
                fatherOfNodeToBeReplaced->right = (Node *) subTreeToLocate;
                sT_removeNode(aux);
                return;
        }
}

/*
 * This function is used to print syntactic trees
 */
void sT_printout(Node *tree) {
        if (tree->left) {
                sT_printout(tree->left);
        }

        if (tree->type > 0 && tree->type < 9) {
//        printf(" ([%p]->[%p,%p]) ", tree,tree->left,tree->right);
                printf(" (%s) ", tree->key);
        }

        if (tree->type == ACTION) {
                printf(" <%s,%f> ", tree->actionName, tree->time);
        }
        if (tree->type == REC_VAR) {
                printf(" %s ", tree->variableName);
        }
        if (tree->type == IN_CHO) {
                printf(" - ");
        }
        if (tree->type == EXT_CHO) {
                printf(" + ");
        }
        if (tree->type == PR_CHO) {
                printf(" *{%f} ", tree->probability);
        }
        if (tree->type == PARALLEL) {
                printf(" ||{");
                int i;
                for (i = 0; i < tree->numberOfActions; i++) {
                        if (i != (tree->numberOfActions - 1)) {
                                printf(" %s ,", tree->actions[i]);
                        } else {
                                printf(" %s ", tree->actions[i]);
                        }
                }
                printf("} ");
        }
        if (tree->type == PREFIX) {
                printf(" . ");
        }
        if (tree->type == SEQ_PROC) {
                printf(" ; ");
        }

        if (tree->right) {
                sT_printout(tree->right);
        }
}
#endif
